package com.lxf.cloudproduct.aop;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lxf.cloudfeign.client.userClient.UserClient;
import com.lxf.cloudproduct.annotate.ProductRateLimit;
import com.lxf.cloudproduct.utils.ProductIpAddressUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @author 罗兴发
 * @data 2025/7/1 15:35
 * @description：限制操作次数
 */
@Aspect
@Component
@Slf4j
public class ProductRateLimitAspect {

    @Resource
    private UserClient userClient;

    @Resource
    private HttpServletRequest request;
    @Resource
    private ProductIpAddressUtils productIpAddressUtils;

    //定义黑名单key前缀
    private static final String BLACKLIST_KEY_PREFIX = "blacklist:";
    //定义白名单key前缀
    private static final String WHITELIST_KEY_PREFIX = "whitelist:";

    @Around("@annotation(rateLimit)")
    public Object rateLimit(ProceedingJoinPoint joinPoint, ProductRateLimit rateLimit) throws Throwable {
        JSONObject js = new JSONObject();

        //获取IP
        String ip = productIpAddressUtils.getIpAddress(request);
        String key = generateKey(joinPoint, ip);
        //黑名单则直接异常
        if (isBlacklisted(ip)) {
            js.put("code",429); //设置响应状态码
            js.put("msg","Too many requests from this IP address");
            return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
        }

        //如果是白名单下的不做限制
        if (isWhitelisted(ip)) {
            return joinPoint.proceed();
        }


        int limit = rateLimit.value();
        int timeout = rateLimit.timeout();

        JSONObject j = new JSONObject();
        j.put("redis_key",key);

        log.info("key值：{}",key);

        String redisData = userClient.getRedisData(j);
        String countStr = "" ;
        if (null!=redisData){
            countStr = new String(redisData);
        }else {
            countStr = new String("0");
        }

        int count = countStr == null ? 0 : Integer.parseInt(countStr);

        if (count < limit) {
            j.put("keys",key);
            j.put("data",String.valueOf(count + 1));
            j.put("times",timeout);
            userClient.addRedisData(j);
            return joinPoint.proceed();
        } else {
            addToBlacklist(ip);
            js.put("code",429); //设置响应状态码
            js.put("msg","Too many requests from this IP address");
            return JSONObject.toJSONString(js, SerializerFeature.WriteMapNullValue);
        }
    }

    private boolean isBlacklisted(String ip) {
        JSONObject j = new JSONObject();
        j.put("keys",BLACKLIST_KEY_PREFIX + ip);
        return userClient.existsRedisData(j);
    }

    private boolean isWhitelisted(String ip) {
        JSONObject j = new JSONObject();
        j.put("keys",WHITELIST_KEY_PREFIX + ip);
        return userClient.existsRedisData(j);
    }

    private void addToBlacklist(String ip) {
        JSONObject j = new JSONObject();
        j.put("keys",BLACKLIST_KEY_PREFIX + ip);
        j.put("data","true");
        j.put("times",1);
        userClient.addRedisData(j);
    }

    private String generateKey(ProceedingJoinPoint joinPoint, String ip) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        return className + ":" + methodName + ":" + ip;
    }
}
